import simpleGit, { SimpleGit, LogResult, DiffResult, StatusResult } from 'simple-git';
import { existsSync } from 'fs';
import { dirname, join } from 'path';

export interface GitCommit {
  hash: string;
  date: string;
  message: string;
  author_name: string;
  author_email: string;
}

export interface GitFileHistory {
  filePath: string;
  commits: GitCommit[];
}

export interface GitDiff {
  filePath: string;
  content: string;
  commitHash: string;
}

export class GitService {
  private git: SimpleGit | null = null;
  private repoPath: string | null = null;

  /**
   * 初始化Git仓库
   * @param filePath 文件路径
   * @returns 是否成功初始化
   */
  async initRepository(filePath: string): Promise<boolean> {
    try {
      const dir = dirname(filePath);
      
      // 检查是否已经是Git仓库
      if (existsSync(join(dir, '.git'))) {
        this.repoPath = dir;
        this.git = simpleGit(dir);
        return true;
      }
      
      // 初始化新的Git仓库
      this.git = simpleGit(dir);
      await this.git.init();
      this.repoPath = dir;
      
      // 创建.gitignore文件，忽略不需要版本控制的文件
      const gitignorePath = join(dir, '.gitignore');
      if (!existsSync(gitignorePath)) {
        await this.git.raw(['touch', '.gitignore']);
        await this.git.add(['.gitignore']);
        await this.git.commit('Initial commit with .gitignore');
      }
      
      return true;
    } catch (error) {
      console.error('Failed to initialize Git repository:', error);
      return false;
    }
  }

  /**
   * 检查文件是否在Git仓库中
   * @param filePath 文件路径
   * @returns 是否在Git仓库中
   */
  async isFileInRepository(filePath: string): Promise<boolean> {
    try {
      if (!this.git || !this.repoPath) {
        await this.initRepository(filePath);
      }
      
      if (!this.git || !this.repoPath) {
        return false;
      }
      
      // 检查文件是否已被跟踪
      const status: StatusResult = await this.git.status();
      const relativePath = filePath.replace(this.repoPath + '/', '');
      
      return status.staged.includes(relativePath) || status.not_added.includes(relativePath);
    } catch (error) {
      console.error('Failed to check if file is in repository:', error);
      return false;
    }
  }

  /**
   * 添加文件到Git仓库
   * @param filePath 文件路径
   * @param message 提交消息
   * @returns 是否成功添加
   */
  async addFile(filePath: string, message: string = 'Update file'): Promise<boolean> {
    try {
      if (!this.git || !this.repoPath) {
        await this.initRepository(filePath);
      }
      
      if (!this.git || !this.repoPath) {
        return false;
      }
      
      const relativePath = filePath.replace(this.repoPath + '/', '');
      await this.git.add(relativePath);
      await this.git.commit(message);
      
      return true;
    } catch (error) {
      console.error('Failed to add file to repository:', error);
      return false;
    }
  }

  /**
   * 获取文件的Git历史记录
   * @param filePath 文件路径
   * @returns 文件历史记录
   */
  async getFileHistory(filePath: string): Promise<GitFileHistory | null> {
    try {
      if (!this.git || !this.repoPath) {
        await this.initRepository(filePath);
      }
      
      if (!this.git || !this.repoPath) {
        return null;
      }
      
      const relativePath = filePath.replace(this.repoPath + '/', '');
      const log: LogResult = await this.git.log({ file: relativePath });
      
      const commits: GitCommit[] = log.all.map(commit => ({
        hash: commit.hash,
        date: commit.date,
        message: commit.message,
        author_name: commit.author_name,
        author_email: commit.author_email
      }));
      
      return {
        filePath,
        commits
      };
    } catch (error) {
      console.error('Failed to get file history:', error);
      return null;
    }
  }

  /**
   * 获取文件在特定提交的内容
   * @param filePath 文件路径
   * @param commitHash 提交哈希
   * @returns 文件内容
   */
  async getFileContentAtCommit(filePath: string, commitHash: string): Promise<string | null> {
    try {
      if (!this.git || !this.repoPath) {
        return null;
      }
      
      const relativePath = filePath.replace(this.repoPath + '/', '');
      const content = await this.git.show([`${commitHash}:${relativePath}`]);
      
      return content;
    } catch (error) {
      console.error('Failed to get file content at commit:', error);
      return null;
    }
  }

  /**
   * 获取文件在两个提交之间的差异
   * @param filePath 文件路径
   * @param commitHash1 第一个提交哈希
   * @param commitHash2 第二个提交哈希
   * @returns 差异内容
   */
  async getFileDiff(filePath: string, commitHash1: string, commitHash2: string): Promise<string | null> {
    try {
      if (!this.git || !this.repoPath) {
        return null;
      }
      
      const relativePath = filePath.replace(this.repoPath + '/', '');
      const diff = await this.git.diff([`${commitHash1}:${relativePath}`, `${commitHash2}:${relativePath}`]);
      
      return diff;
    } catch (error) {
      console.error('Failed to get file diff:', error);
      return null;
    }
  }

  /**
   * 获取仓库状态
   * @returns 仓库状态
   */
  async getRepositoryStatus(): Promise<any> {
    try {
      if (!this.git || !this.repoPath) {
        return null;
      }
      
      return await this.git.status();
    } catch (error) {
      console.error('Failed to get repository status:', error);
      return null;
    }
  }

  /**
   * 检查是否有未提交的更改
   * @returns 是否有未提交的更改
   */
  async hasUncommittedChanges(): Promise<boolean> {
    try {
      const status = await this.getRepositoryStatus();
      if (!status) {
        return false;
      }
      
      return status.files.length > 0;
    } catch (error) {
      console.error('Failed to check for uncommitted changes:', error);
      return false;
    }
  }

  /**
   * 提交当前更改
   * @param message 提交消息
   * @returns 是否成功提交
   */
  async commitChanges(message: string): Promise<boolean> {
    try {
      if (!this.git || !this.repoPath) {
        return false;
      }
      
      await this.git.add('.');
      await this.git.commit(message);
      
      return true;
    } catch (error) {
      console.error('Failed to commit changes:', error);
      return false;
    }
  }

  /**
   * 获取Git状态
   * @param repoPath 仓库路径
   * @returns Git状态
   */
  async getStatus(repoPath: string): Promise<any> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return null;
      }
      
      return await this.git.status();
    } catch (error) {
      console.error('Failed to get git status:', error);
      return null;
    }
  }

  /**
   * 添加文件到Git
   * @param repoPath 仓库路径
   * @param files 文件列表
   * @returns 是否成功
   */
  async addFiles(repoPath: string, files: string[]): Promise<boolean> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return false;
      }
      
      await this.git.add(files);
      return true;
    } catch (error) {
      console.error('Failed to add files:', error);
      return false;
    }
  }

  /**
   * 提交更改
   * @param repoPath 仓库路径
   * @param message 提交消息
   * @returns 是否成功
   */
  async commit(repoPath: string, message: string): Promise<boolean> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return false;
      }
      
      await this.git.commit(message);
      return true;
    } catch (error) {
      console.error('Failed to commit:', error);
      return false;
    }
  }

  /**
   * 获取提交历史
   * @param repoPath 仓库路径
   * @param limit 限制数量
   * @returns 提交历史
   */
  async getCommitHistory(repoPath: string, limit?: number): Promise<GitCommit[]> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return [];
      }
      
      const log = await this.git.log({ maxCount: limit || 10 });
      return log.all.map(commit => ({
        hash: commit.hash,
        date: commit.date,
        message: commit.message,
        author_name: commit.author_name,
        author_email: commit.author_email
      }));
    } catch (error) {
      console.error('Failed to get commit history:', error);
      return [];
    }
  }

  /**
   * 创建分支
   * @param repoPath 仓库路径
   * @param branchName 分支名称
   * @returns 是否成功
   */
  async createBranch(repoPath: string, branchName: string): Promise<boolean> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return false;
      }
      
      await this.git.checkoutLocalBranch(branchName);
      return true;
    } catch (error) {
      console.error('Failed to create branch:', error);
      return false;
    }
  }

  /**
   * 切换分支
   * @param repoPath 仓库路径
   * @param branchName 分支名称
   * @returns 是否成功
   */
  async switchBranch(repoPath: string, branchName: string): Promise<boolean> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return false;
      }
      
      await this.git.checkout(branchName);
      return true;
    } catch (error) {
      console.error('Failed to switch branch:', error);
      return false;
    }
  }

  /**
   * 获取当前分支
   * @param repoPath 仓库路径
   * @returns 当前分支名称
   */
  async getCurrentBranch(repoPath: string): Promise<string> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return '';
      }
      
      const status = await this.git.status();
      return status.current || '';
    } catch (error) {
      console.error('Failed to get current branch:', error);
      return '';
    }
  }

  /**
   * 获取远程分支
   * @param repoPath 仓库路径
   * @returns 远程分支列表
   */
  async getRemoteBranches(repoPath: string): Promise<string[]> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return [];
      }
      
      const branches = await this.git.branch(['-r']);
      return branches.all.filter(branch => branch.startsWith('origin/'));
    } catch (error) {
      console.error('Failed to get remote branches:', error);
      return [];
    }
  }

  /**
   * 拉取更改
   * @param repoPath 仓库路径
   * @param remote 远程名称
   * @param branch 分支名称
   * @returns 是否成功
   */
  async pull(repoPath: string, remote?: string, branch?: string): Promise<boolean> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return false;
      }
      
      await this.git.pull(remote, branch);
      return true;
    } catch (error) {
      console.error('Failed to pull:', error);
      return false;
    }
  }

  /**
   * 推送更改
   * @param repoPath 仓库路径
   * @param remote 远程名称
   * @param branch 分支名称
   * @returns 是否成功
   */
  async push(repoPath: string, remote?: string, branch?: string): Promise<boolean> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return false;
      }
      
      await this.git.push(remote, branch);
      return true;
    } catch (error) {
      console.error('Failed to push:', error);
      return false;
    }
  }

  /**
   * 克隆仓库
   * @param url 仓库URL
   * @param targetPath 目标路径
   * @returns 是否成功
   */
  async clone(url: string, targetPath: string): Promise<boolean> {
    try {
      const git = simpleGit();
      await git.clone(url, targetPath);
      
      // 初始化当前实例
      this.repoPath = targetPath;
      this.git = simpleGit(targetPath);
      
      return true;
    } catch (error) {
      console.error('Failed to clone repository:', error);
      return false;
    }
  }

  /**
   * 检查是否是仓库
   * @param repoPath 仓库路径
   * @returns 是否是仓库
   */
  async isRepository(repoPath: string): Promise<boolean> {
    try {
      if (!this.git || this.repoPath !== repoPath) {
        await this.initRepository(repoPath);
      }
      
      if (!this.git) {
        return false;
      }
      
      const status = await this.git.status();
      return !!status;
    } catch (error) {
      return false;
    }
  }
}

// 导出单例实例
export const gitService = new GitService();